package main

import (
    "fmt"
    "strconv"
    "strings"
    "bytes"
    "io"
    "crypto/rand"
    "crypto/aes"
    "crypto/cipher"
    "encoding/base64"
    "brick.dgd/brick/uuid"
)

func main() {
    id, _ := getUUIDStr()
    newNumber, _ := strconv.ParseUint("100", 10, 64)
    fmt.Printf("test: %s, %d\n\r", id, newNumber)
    isDiffAppSerID("PZmqS19FuonE2skY$oDBw65BXDuIGHNdK24IEX_RKEHVY", "PZmqS19FuonE2skY$system")

    var aeskey = []byte("0123456789012345")
    ss, _ := Dncrypt("C6876D1EDF9A1F58308DDB675ACA98DFA448AD0EF0E45EE159BF3F3494472099", aeskey)
    fmt.Println(ss)
}


//使用PKCS7进行填充，IOS也是7
func PKCS7Padding(ciphertext []byte, blockSize int) []byte {
   padding := blockSize - len(ciphertext) % blockSize
   padtext := bytes.Repeat([]byte{byte(padding)}, padding)
   return append(ciphertext, padtext...)
}

func PKCS7UnPadding(origData []byte) []byte {
   length := len(origData)
   unpadding := int(origData[length-1])
   return origData[:(length - unpadding)]
}

//aes加密，填充秘钥key的16位，24,32分别对应AES-128, AES-192, or AES-256.
func AesCBCEncrypt(rawData,key []byte) ([]byte, error) {
   block, err := aes.NewCipher(key)
   if err != nil {
       panic(err)
   }

   //填充原文
   blockSize := block.BlockSize()
   rawData = PKCS7Padding(rawData, blockSize)
   //初始向量IV必须是唯一，但不需要保密
   cipherText := make([]byte,blockSize+len(rawData))
   //block大小 16
   iv := cipherText[:blockSize]
   if _, err := io.ReadFull(rand.Reader,iv); err != nil {
       panic(err)
   }

   //block大小和初始向量大小一定要一致
   mode := cipher.NewCBCEncrypter(block,iv)
   mode.CryptBlocks(cipherText[blockSize:],rawData)

   return cipherText, nil
}

func AesCBCDncrypt(encryptData, key []byte) ([]byte,error) {
   block, err := aes.NewCipher(key)
   if err != nil {
       panic(err)
   }

   blockSize := block.BlockSize()

   if len(encryptData) < blockSize {
       panic("ciphertext too short")
   }
   iv := encryptData[:blockSize]
   encryptData = encryptData[blockSize:]

   // CBC mode always works in whole blocks.
   if len(encryptData)%blockSize != 0 {
       panic("ciphertext is not a multiple of the block size")
   }

   mode := cipher.NewCBCDecrypter(block, iv)

   // CryptBlocks can work in-place if the two arguments are the same.
   mode.CryptBlocks(encryptData, encryptData)
   //解填充
   encryptData = PKCS7UnPadding(encryptData)
   return encryptData,nil
}


func Encrypt(rawData,key []byte) (string,error) {
   data, err:= AesCBCEncrypt(rawData,key)
   if err != nil {
       return "",err
   }
   return base64.StdEncoding.EncodeToString(data),nil
}

func Dncrypt(rawData string,key []byte) (string,error) {
   data,err := base64.StdEncoding.DecodeString(rawData)
   if err != nil {
       return "",err
   }
   dnData,err := AesCBCDncrypt(data,key)
   if err != nil {
       return "",err
   }
   return string(dnData),nil
}

func getUUIDStr() (string, error) {
    id, e := uuid.Get(12)
    if nil != e {
        return "" , e
    }
    return strconv.FormatUint(id, 10), nil
}

func isDiffAppSerID(fa, ta string) string {
    fromSerIdentifier := strings.Split(fa, "$")
    fmt.Println(fromSerIdentifier)
    toSerIdentifier := strings.Split(ta, "$")
    fmt.Println(toSerIdentifier)
    if 0 == len(fromSerIdentifier) || len(fromSerIdentifier) != len(toSerIdentifier) || fromSerIdentifier[0] != toSerIdentifier[0] {
        fmt.Printf("请求参数错误，通信双方用户唯一标识并非属于同一应用服务下！FromAccount：%s，ToAccount：%s\n", fa, ta)
        return ""
    }
    return fromSerIdentifier[0]
}
